home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 06 General Architectures / 03 Alexander / LoadBalance.cpp next >
Encoding:
C/C++ Source or Header  |  2001-08-18  |  16.4 KB  |  795 lines

  1. /*********************************************************************\
  2.  *
  3.  * Copyright Stormfront Studios, Inc.  Confidential.
  4.  *
  5.  *   This source code is proprietary and confidential under
  6.  * appropriate laws.  No duplication is allowed without the
  7.  * express written permission of Stormfront Studios, Inc.
  8.  * All Rights Reserved.
  9.  *
  10.  *
  11.  * $Workfile: AIUpdate.cpp $
  12.  *
  13.  * $Modtime: 7/02/01 4:05p $
  14.  *
  15.  * $Author: Balexander $
  16.  *
  17.  *
  18.  * Description:
  19.  *
  20.  *   This source file contains the AI update module class.
  21.  *
  22.  *
  23. \*********************************************************************/
  24.  
  25. #include <stdio.h>
  26. #include <float.h>
  27.  
  28. #include "LoadBalance.h"
  29.  
  30. ///////////////////////////////////////////////////////////////////////
  31. // The AI Update Module
  32.  
  33. ExecutionModule            gAIExecutionModule;
  34.  
  35. ///////////////////////////////////////////////////////////////////////
  36. // AI Update Module Profiling
  37.  
  38. #ifdef _DEBUG
  39.  
  40. #define PROFILE_INIT(data)            \
  41.     {                                \
  42.         data.TotalTime = 0;            \
  43.         data.MinTime = FLT_MAX;        \
  44.         data.MaxTime = -FLT_MAX;    \
  45.         data.Count = 0;                \
  46.         data.Name = NULL;            \
  47.     }
  48.  
  49. #define PROFILE_RELEASE(data)    ((void)0)
  50.  
  51. #define PROFILE_START(data)    // TBD - Record system ticks
  52.  
  53. #define PROFILE_END(data)                                            \
  54.     {                                                                \
  55.         float ExecTime = 0; /* Get system ticks */                    \
  56.         data.TotalTime += ExecTime;                                    \
  57.         if (ExecTime < data.MinTime)    data.MinTime = ExecTime;    \
  58.         if (ExecTime > data.MaxTime)    data.MaxTime = ExecTime;    \
  59.         data.Count++;                                                \
  60.     }
  61.  
  62. #define PROFILE_GROUP_INIT(data)        \
  63.     {                                    \
  64.         data.TotalTime = 0;                \
  65.         data.MaxTime = -FLT_MAX;        \
  66.         data.FrameCount = 0;            \
  67.         data.LastFrame = ~0;            \
  68.         data.LastFrameTotalTime = 0;    \
  69.     }
  70.  
  71. #define PROFILE_GROUP_RELEASE(data)    ((void)0)
  72.  
  73. #define PROFILE_GROUP_FRAME_START(data)                                \
  74.     {                                                                \
  75.         data.FrameTaskCount = 0;                                \
  76.     }
  77.  
  78. #define PROFILE_GROUP_FRAME_END(data)    ((void)0)
  79.  
  80. #define PROFILE_GROUP_START(data)                                    \
  81.     {                                                                \
  82.         if (data.LastFrame != gAIExecutionModule.GetFrames())        \
  83.         {                                                            \
  84.             data.LastFrame = gAIExecutionModule.GetFrames();        \
  85.             data.LastFrameTotalTime = data.TotalTime;                \
  86.             data.FrameCount++;                                        \
  87.         }                                                            \
  88.         /* Record system ticks */                                    \
  89.     }
  90.  
  91. #define PROFILE_GROUP_END(data)                                        \
  92.     {                                                                \
  93.         float ExecTime = 0; /* Get system ticks */                    \
  94.         data.TotalTime += ExecTime;                                    \
  95.         data.FrameTaskCount++;                                        \
  96.         ExecTime = data.TotalTime - data.LastFrameTotalTime;        \
  97.         if (ExecTime > data.MaxTime)    data.MaxTime = ExecTime;    \
  98.     }
  99.  
  100. void PROFILE_INIT_MODULE( void )
  101. {
  102.     // Add code here
  103. }
  104.  
  105. void PROFILE_RELEASE_MODULE( void )
  106. {
  107.     // Add code here
  108. }
  109.  
  110.  
  111.  
  112. #else
  113.  
  114. #define PROFILE_INIT_MODULE()        ((void)0)
  115. #define PROFILE_RELEASE_MODULE()    ((void)0)
  116. #define PROFILE_INIT(data)            ((void)0)
  117. #define PROFILE_RELEASE(data)        ((void)0)
  118. #define PROFILE_START(data)            ((void)0)
  119. #define PROFILE_END(data)            ((void)0)
  120.  
  121. #define PROFILE_GROUP_INIT(data)        ((void)0)
  122. #define PROFILE_GROUP_RELEASE(data)        ((void)0)
  123. #define PROFILE_GROUP_FRAME_START(data)    ((void)0)
  124. #define PROFILE_GROUP_FRAME_END(data)    ((void)0)
  125. #define PROFILE_GROUP_START(data)        ((void)0)
  126. #define PROFILE_GROUP_END(data)            ((void)0)
  127.  
  128. #endif
  129.  
  130.  
  131. ///////////////////////////////////////////////////////////////////////
  132. // AI update module class
  133.  
  134. //
  135. //  Construction
  136. //
  137.  
  138. //
  139. //  This function handles AI update initialization.
  140. //
  141.  
  142. bool ExecutionModule::Init( void )
  143. {
  144.     mTime = 0;
  145.     mTicks = 0;
  146.     mFrames = 0;
  147.  
  148.     mpScheduledTasks = NULL;
  149.     mpExecutingTask = NULL;
  150.  
  151.     // Init profiling
  152.     PROFILE_INIT_MODULE();
  153.     PROFILE_INIT( GetProfileData() );
  154.     AI_UPDATE_SET_PROFILE_NAME( *this, "AI Update Module" );
  155.  
  156.     return( true );
  157. }
  158.  
  159.  
  160. //
  161. //  This function handles AI update release.
  162. //
  163.  
  164. bool ExecutionModule::Release( void )
  165. {
  166.     // Clear Task schedule
  167.     while (mpScheduledTasks != NULL)
  168.     {
  169.         UnscheduleTask( mpScheduledTasks );
  170.     }
  171.  
  172.     // Remove all groups
  173.     while (mpFirstGroup != NULL)
  174.     {
  175.         DetachGroup( mpFirstGroup );
  176.     }
  177.  
  178.     PROFILE_RELEASE( GetProfileData() );
  179.     PROFILE_RELEASE_MODULE();
  180.  
  181.     return( true );
  182. }
  183.  
  184.  
  185. //
  186. //  Update
  187. //
  188.  
  189. void ExecutionModule::Update( unsigned long dt )
  190. {
  191.     PROFILE_START( GetProfileData() );
  192.     if (dt)
  193.     {
  194.         float fdt = (float)dt/1000.0f;
  195.  
  196.         mTime += fdt;
  197.         mTicks += dt;
  198.         mFrames++;
  199.  
  200.         #ifdef _DEBUG
  201.         {
  202.             for (SchedulingGroup * group = mpFirstGroup; group != NULL; group = group->GetNext())
  203.             {
  204.                 PROFILE_GROUP_FRAME_START( group->GetGroupProfileData() );
  205.             }
  206.         }
  207.         #endif
  208.  
  209.         // Run all expired scheduled Tasks
  210.         while (        (mpScheduledTasks != NULL)
  211.                 &&    (mpScheduledTasks->GetTime() < mTime) )
  212.         {
  213.             // Remove Task from queue
  214.             mpExecutingTask = mpScheduledTasks;
  215.             mpScheduledTasks = mpScheduledTasks->mpScheduledNext;
  216.  
  217.             mpExecutingTask->mScheduled = false;
  218.  
  219.             SchedulingGroup * executingGroup = mpExecutingTask->GetGroup();
  220.  
  221.             if (executingGroup != NULL)
  222.             {
  223.                 PROFILE_GROUP_START( executingGroup->GetGroupProfileData() );
  224.             }
  225.  
  226.                 PROFILE_START( mpExecutingTask->GetProfileData() );
  227.  
  228.                     mpExecutingTask->Run( (mpExecutingTask->mLastTime != 0) ? (mTime - mpExecutingTask->mLastTime) : 0 );
  229.  
  230.                 PROFILE_END( mpExecutingTask->GetProfileData() );
  231.  
  232.             if (executingGroup != NULL)
  233.             {
  234.                 PROFILE_GROUP_END( executingGroup->GetGroupProfileData() );
  235.             }
  236.  
  237.             // If the Task has not gone away, remove it from the schedule.
  238.             mpExecutingTask->mLastTime = mTime;
  239.  
  240.             mpExecutingTask = NULL;        // JIC
  241.         }
  242.  
  243.         // Run all groups to rescedule Tasks.
  244.         for (SchedulingGroup * group = mpFirstGroup; group != NULL; group = group->GetNext())
  245.         {
  246.             PROFILE_START( group->GetProfileData() );
  247.             group->Schedule( this );
  248.             PROFILE_END( group->GetProfileData() );
  249.             PROFILE_GROUP_FRAME_END( group->GetProfileData() );
  250.         }
  251.     }
  252.     PROFILE_END( GetProfileData() );
  253. }
  254.  
  255.  
  256. //
  257. //  Attach/Detach groups
  258. //
  259.  
  260. bool ExecutionModule::AttachGroup( SchedulingGroup * group )
  261. {
  262.     for (SchedulingGroup * curGroup = mpFirstGroup; curGroup != NULL; curGroup = curGroup->mpNext)
  263.     {
  264.         if (curGroup == group)
  265.         {
  266.             // Already in the group.
  267.             return false;
  268.         }
  269.     }
  270.  
  271.     // Add to front of list.
  272.     group->mpNext = mpFirstGroup;
  273.     mpFirstGroup = group;
  274.  
  275.     return true;
  276. }
  277.  
  278. bool ExecutionModule::DetachGroup( SchedulingGroup * group )
  279. {
  280.     for (SchedulingGroup ** DelAt = &mpFirstGroup; *DelAt != NULL; DelAt = &((*DelAt)->mpNext))
  281.     {
  282.         if (*DelAt == group)
  283.         {
  284.             *DelAt = group->mpNext;
  285.             group->mpNext = NULL;
  286.             return true;
  287.         }
  288.     }
  289.  
  290.     return false;
  291. }
  292.  
  293. //
  294. //  Schedule a Task
  295. //
  296.  
  297. bool ExecutionModule::ScheduleTask( Task * task )
  298. {
  299.     // Insert sort the task by time.
  300.     if (task->IsScheduled())
  301.     {
  302.         return false;
  303.     }
  304.  
  305.     for (Task ** AddAt = &mpScheduledTasks; *AddAt != NULL; AddAt = &((*AddAt)->mpScheduledNext))
  306.     {
  307.         if ((*AddAt)->GetTime() > task->GetTime())
  308.         {
  309.             break;
  310.         }
  311.     }
  312.  
  313.     // Add at location found.
  314.     task->mpScheduledNext = *AddAt;
  315.     *AddAt = task;
  316.     task->mScheduled = true;
  317.     return true;
  318. }
  319.  
  320. //
  321. //  Unschedule a previously scheduled Task
  322. //
  323.  
  324. bool ExecutionModule::UnscheduleTask( Task * task )
  325. {
  326.     if (!task->IsScheduled())
  327.     {
  328.         return false;
  329.     }
  330.  
  331.     for (Task ** DelAt = &mpScheduledTasks; *DelAt != NULL; DelAt = &((*DelAt)->mpScheduledNext))
  332.     {
  333.         if (*DelAt == task)
  334.         {
  335.             *DelAt = task->mpScheduledNext;
  336.             task->mpScheduledNext = NULL;
  337.             task->mScheduled = false;
  338.             return true;
  339.         }
  340.     }
  341.  
  342.     return false;
  343. }
  344.  
  345.  
  346. ///////////////////////////////////////////////////////////////////////
  347. // Scheduling Group Class
  348.  
  349. // initialization/release
  350. bool SchedulingGroup::Init( void )
  351. {
  352.     PROFILE_INIT( GetProfileData() );
  353.     PROFILE_GROUP_INIT( GetGroupProfileData() );
  354.     mpFirstTask = NULL;
  355.     mTaskCount = 0;
  356.     return true;
  357. }
  358.  
  359. bool SchedulingGroup::Release( void )
  360. {
  361.     gAIExecutionModule.DetachGroup( this );
  362.     while (mpFirstTask != NULL)
  363.     {
  364.         DetachTask( mpFirstTask );
  365.     }
  366.     PROFILE_GROUP_RELEASE( GetGroupProfileData() );
  367.     PROFILE_RELEASE( GetProfileData() );
  368.     return true;
  369. }
  370.  
  371. bool SchedulingGroup::AttachTask( Task * task )
  372. {
  373.     for (Task * curTask = mpFirstTask; curTask != NULL; curTask = curTask->mpGroupNext)
  374.     {
  375.         if (curTask == task)
  376.         {
  377.             // Already in the group.
  378.             return false;
  379.         }
  380.     }
  381.  
  382.     // Add to front of list.
  383.     task->mpGroupNext = mpFirstTask;
  384.     mpFirstTask = task;
  385.     task->mpGroup  = this;
  386.     mTaskCount++;
  387.  
  388.     return true;
  389. }
  390.  
  391. bool SchedulingGroup::DetachTask( Task * task )
  392. {
  393.     for (Task ** DelAt = &mpFirstTask; *DelAt != NULL; DelAt = &((*DelAt)->mpGroupNext))
  394.     {
  395.         if (*DelAt == task)
  396.         {
  397.             *DelAt = task->mpGroupNext;
  398.             task->mpGroupNext = NULL;
  399.             task->mpGroup = NULL;
  400.             mTaskCount--;
  401.             return true;
  402.         }
  403.     }
  404.  
  405.     return false;
  406. }
  407.  
  408. void SchedulingGroup::SetTaskTime( Task * task, float time )
  409. {
  410.     task->mTime = time;
  411. }
  412.  
  413. ///////////////////////////////////////////////////////////////////////
  414. // Task Class
  415.  
  416. bool Task::Init( void )
  417. {
  418.     PROFILE_INIT( GetProfileData() );
  419.     mTime = 0;
  420.     mLastTime = 0;
  421.     mScheduled = false;
  422.     mpGroup = NULL;
  423.     mpGroupNext = NULL;
  424.     mpScheduledNext = NULL;
  425.     return true;
  426. }
  427.  
  428. bool Task::Release( void )
  429. {
  430.     if (mpGroup != NULL)
  431.     {
  432.         mpGroup->DetachTask( this );
  433.     }
  434.     gAIExecutionModule.UnscheduleTask( this );
  435.     PROFILE_RELEASE( GetProfileData() );
  436.     return true;
  437. }
  438.  
  439.  
  440.  
  441. ///////////////////////////////////////////////////////////////////////
  442. // AI Update Every Frame
  443.  
  444. void EveryFrameGroup::Schedule( ExecutionModule * module )
  445. {
  446.     // Schedule all Tasks, setting their fire times to 0.
  447.     // This will ensure that they are fired next Update module call.
  448.  
  449.     for (Task * task = mpFirstTask; task != NULL; task = task->GetGroupNext())
  450.     {
  451.         if (!task->IsScheduled())
  452.         {
  453.             SetTaskTime( task, 0 );
  454.             module->ScheduleTask( task );
  455.         }
  456.     }
  457. }
  458.  
  459.  
  460. ///////////////////////////////////////////////////////////////////////
  461. // AI Update Count
  462.  
  463. bool CountGroup::Init( int count )
  464. {
  465.     mCount = count;
  466.     mpCurrentTask = NULL;
  467.     return SchedulingGroup::Init();
  468. }
  469.  
  470. bool CountGroup::Release( void )
  471. {
  472.     mpCurrentTask = NULL;
  473.     return SchedulingGroup::Release();
  474. }
  475.  
  476. bool CountGroup::DetachTask( Task * task )
  477. {
  478.     // If we are detaching a 
  479.     if (mpCurrentTask == task)
  480.     {
  481.         mpCurrentTask = mpCurrentTask->GetGroupNext();
  482.         if (mpCurrentTask == NULL)
  483.         {
  484.             mpCurrentTask = GetFirstTask();
  485.         }
  486.     }
  487.  
  488.     return SchedulingGroup::DetachTask( task );
  489. }
  490.  
  491. void CountGroup::Schedule( ExecutionModule * module )
  492. {
  493.     if (GetFirstTask() != NULL)
  494.     {
  495.         if (mpCurrentTask == NULL)
  496.         {
  497.             // Initialize current Task
  498.             mpCurrentTask = GetFirstTask();
  499.         }
  500.  
  501.         Task * start = mpCurrentTask;
  502.  
  503.         int count = mCount;
  504.         while (count)
  505.         {
  506.             if (!mpCurrentTask->IsScheduled())
  507.             {
  508.                 // NOt scheduled, so schedule it.
  509.                 SetTaskTime( mpCurrentTask, 0 );
  510.                 module->ScheduleTask( mpCurrentTask );
  511.                 count--;
  512.             }
  513.  
  514.             // Move to next Task.
  515.             mpCurrentTask = mpCurrentTask->GetGroupNext();
  516.             if (mpCurrentTask == NULL)
  517.             {
  518.                 // Wrap around
  519.                 mpCurrentTask = GetFirstTask();
  520.             }
  521.             if (mpCurrentTask == start)
  522.             {
  523.                 // Back at start, so stop.
  524.                 break;
  525.             }
  526.         }
  527.     }
  528. }
  529.  
  530.  
  531. ///////////////////////////////////////////////////////////////////////
  532. // AI Update Spread
  533.  
  534. bool SpreadGroup::Init( float period )
  535. {
  536.     mPeriod = period;
  537.     mTime = 0;
  538.     return SchedulingGroup::Init();
  539. }
  540.  
  541. bool SpreadGroup::AttachTask( Task * task )
  542. {
  543.     if (SchedulingGroup::AttachTask( task ))
  544.     {
  545.         return true;
  546.     }
  547.  
  548.     return false;
  549. }
  550.  
  551. bool SpreadGroup::DetachTask( Task * task )
  552. {
  553.     if (SchedulingGroup::DetachTask( task ))
  554.     {
  555.         return true;
  556.     }
  557.  
  558.     return false;
  559. }
  560.  
  561. void SpreadGroup::Schedule( ExecutionModule * module )
  562. {
  563.     if (GetTaskCount() > 0)
  564.     {
  565.         float dt = mPeriod / GetTaskCount();
  566.  
  567.         // Adjust time to make sure its past the current time.
  568.         mTime += (int((module->GetTime() - mTime) / dt) + 1) * dt;
  569.  
  570.         for (Task * task = mpFirstTask; task != NULL; task = task->GetGroupNext())
  571.         {
  572.             if (!task->IsScheduled())
  573.             {
  574.                 SetTaskTime( task, mTime );
  575.                 module->ScheduleTask( task );
  576.                 mTime += dt;
  577.             }
  578.         }
  579.     }
  580. }
  581.  
  582.  
  583. ///////////////////////////////////////////////////////////////////////
  584. // Timed Update Task
  585.  
  586. bool TimedTask::Init()
  587. {
  588.     Reset();
  589.     return Task::Init();
  590. }
  591.  
  592. //
  593. // Reset all stats.
  594. //
  595.  
  596. void TimedTask::Reset( void )
  597. {
  598.     mLastTime = 0;
  599.     mTotalTime = 0;
  600.     mExecutionCount = 0;
  601. }
  602.  
  603. //
  604. // This Task will time the run of the Execute Task below.
  605. //
  606.  
  607. void TimedTask::Run( float dt )
  608. {
  609.     // Record system ticks
  610.  
  611.     Execute( dt );
  612.  
  613.     mLastTime = 0; // Get system ticks
  614.  
  615.     mTotalTime += mLastTime;
  616.     mExecutionCount++;
  617. }
  618.  
  619.  
  620. ///////////////////////////////////////////////////////////////////////
  621. // AI Max Time Update
  622.  
  623. bool MaxTimeGroup::Init( float period )
  624. {
  625.     mMaxTime = period;
  626.     mpCurrentTask = NULL;
  627.     return SchedulingGroup::Init();
  628. }
  629.  
  630. bool MaxTimeGroup::Release( void )
  631. {
  632.     mpCurrentTask = NULL;
  633.     return SchedulingGroup::Release();
  634. }
  635.  
  636. bool MaxTimeGroup::AttachTask( TimedTask * task )
  637. {
  638.     // Just call the protected version
  639.     return AttachTask( (Task *)task );
  640. }
  641.  
  642. bool MaxTimeGroup::DetachTask( TimedTask * task )
  643. {
  644.     // Just call the protected version
  645.     return DetachTask( (Task *)task );
  646. }
  647.  
  648. bool MaxTimeGroup::AttachTask( Task * task )
  649. {
  650.     return SchedulingGroup::AttachTask( task );
  651. }
  652.  
  653. bool MaxTimeGroup::DetachTask( Task * task )
  654. {
  655.     if (mpCurrentTask == task)
  656.     {
  657.         mpCurrentTask = mpCurrentTask->GetGroupNext();
  658.         if (mpCurrentTask == NULL)
  659.         {
  660.             mpCurrentTask = GetFirstTask();
  661.         }
  662.     }
  663.  
  664.     return SchedulingGroup::DetachTask( task );
  665. }
  666.  
  667. void MaxTimeGroup::Schedule( ExecutionModule * module )
  668. {
  669.     if (GetFirstTask() != NULL)
  670.     {
  671.         float ScheduledTime = 0;
  672.         int ScheduleCount = 0;
  673.  
  674.         if (mpCurrentTask == NULL)
  675.         {
  676.             // Initialize current Task
  677.             mpCurrentTask = GetFirstTask();
  678.         }
  679.  
  680.         Task * start = mpCurrentTask;
  681.  
  682.         while (ScheduledTime < mMaxTime)
  683.         {
  684.             if (!mpCurrentTask->IsScheduled())
  685.             {
  686.                 // Not scheduled, so schedule it.
  687.                 TimedTask * timedTask = (TimedTask *)mpCurrentTask;
  688.                 
  689.                 float NewTotal = ScheduledTime + timedTask->GetLastExecutionTime();
  690.  
  691.                 if (    (ScheduledTime < mMaxTime)    // We do not exceed the time limit.
  692.                     ||    (ScheduleCount == 0) )    // It's the only thing to schedule.
  693.                 {
  694.                     SetTaskTime( mpCurrentTask, 0 );
  695.                     module->ScheduleTask( mpCurrentTask );
  696.                     ScheduledTime = NewTotal;
  697.                     ScheduleCount++;
  698.                 }
  699.             }
  700.  
  701.             // Move to next Task.
  702.             mpCurrentTask = mpCurrentTask->GetGroupNext();
  703.             if (mpCurrentTask == NULL)
  704.             {
  705.                 // Wrap around
  706.                 mpCurrentTask = GetFirstTask();
  707.             }
  708.             if (mpCurrentTask == start)
  709.             {
  710.                 // Back at start, so stop.
  711.                 break;
  712.             }
  713.         }
  714.     }
  715. }
  716.  
  717. ///////////////////////////////////////////////////////////////////////
  718. // Variable Delay Task
  719.  
  720. bool VarDelayTask::Init()
  721. {
  722.     mDelay = 1.0f / 4.0f;    // Default delay of 1/4 of a second.
  723.     return Task::Init();
  724. }
  725.  
  726.  
  727. ///////////////////////////////////////////////////////////////////////
  728. // AI Variable Delay Update Group
  729.  
  730. bool VarDelayGroup::Init( void )
  731. {
  732.     mTime = 0;
  733.     return SchedulingGroup::Init();
  734. }
  735.  
  736. bool VarDelayGroup::AttachTask( VarDelayTask * task )
  737. {
  738.     // Just call the protected version
  739.     return AttachTask( (Task *)task );
  740. }
  741.  
  742. bool VarDelayGroup::DetachTask( VarDelayTask * task )
  743. {
  744.     // Just call the protected version
  745.     return DetachTask( (Task *)task );
  746. }
  747.  
  748. bool VarDelayGroup::AttachTask( Task * task )
  749. {
  750.     return SchedulingGroup::AttachTask( task );
  751. }
  752.  
  753. bool VarDelayGroup::DetachTask( Task * task )
  754. {
  755.     return SchedulingGroup::DetachTask( task );
  756. }
  757.  
  758. void VarDelayGroup::Schedule( ExecutionModule * module )
  759. {
  760.     if (mpFirstTask != NULL)
  761.     {
  762.         const float dt = 1.0f / 30.0f;
  763.  
  764.         // Adjust time to make sure its past the current time.
  765.         mTime += (int((module->GetTime() - mTime) / dt) + 1) * dt;
  766.  
  767.         for (Task * task = mpFirstTask; task != NULL; task = task->GetGroupNext())
  768.         {
  769.             if (!task->IsScheduled())
  770.             {
  771.                 if (task->GetTime() == 0)
  772.                 {
  773.                     // First time the task is scheduled.
  774.                     // In order to attempt to prevent tasks from executing all on
  775.                     // the same frame, use the mTime to stagger the tasks
  776.                     SetTaskTime( task, mTime );
  777.                     mTime += dt;
  778.                 }
  779.                 else
  780.                 {
  781.                     // Task has been schedule before, use task delay to 
  782.                     // reschedule.
  783.                     VarDelayTask * DelayTask = (VarDelayTask *)task;
  784.                     float NewTime = task->GetTime();
  785.                     NewTime += (int((module->GetTime() - task->GetTime()) / DelayTask->GetDelay()) + 1) * DelayTask->GetDelay();
  786.                     SetTaskTime( task, NewTime );
  787.                 }
  788.                 module->ScheduleTask( task );
  789.             }
  790.         }
  791.     }
  792. }
  793.  
  794.  
  795.